BASIC TENLINER CONTEST 2020
Title: Labyrinten
Language: Basic v2 for Commodore 64
Category: PUR80
Author: Felix Nardella


Goal:
====
The goal of this game is to find the treasure indicated with the $
character in reverse.
When you find the treasure, the background color changes and the treasure
moves to another point in the maze. So, you have to move the little man
again to reach the treasure.

Maze construction technique:
===========================
I used the backtracking algorithm.

How to run the game:
===================
To run the game I used the C64 Emulator VICE v3.2.
Here's how to use it:
 Click : File -> Attach disk image -> Drive 8
 Select: labyrinten.d64
 Click : Attach

Now, just as you would with a normal Commodore 64, you can type:
 LOAD"$",8                (to load the directory)
 LOAD"LABYRINTEN",8       (to load the game)
 LIST                     (to view the directory or game listing)
 RUN                      (to run the game)

Then the message WAIT appears, indicating that you have to wait for
some characters to be moved from ROM to RAM to change the shape of a 
character.
In addition, the entire labyrint construction must be waited for.
The little man in the complete labyrinth appears, in the end.

Keys to use:
===========
To move the little man you have to use the keyboard keys J and L to
 go to the right and left.
The 'I' and 'K' keys to go up and down.


Compressed source:
=================
0a=1186:w=163:v=56334:a$="{reverse on}{yellow}
":d$=a$:?"{white}{clear}{reverse on}wait...":b$="{white}{reverse on}#":c$=b$:pOv,pE(v)aN254
1fOz=1to37:b$=b$+c$:a$=a$+d$:nE:pO1,pE(1)aN251:fOi=0to367:pOi+15368,pE(i+54280)
2nE:pO1,pE(1)or4:a(0)=-2:a(1)=-80:a(3)=80:e$=b$+c$+c$:?e$;:fOf=0to20:?c$a$c$;
3nE:?e$;:y=53280:pOv,pE(v)or1:pOy-8,pE(y-8)or14:fOi=0to7:rEf:pO15392+i,f:nE
4a(2)=2:n=32:b=a+a(j):ifpE(b)=w-3tHpOb,j:pOa+a(j)/2,n:a=b:j=int(rN(0)*4):g=j:gO4
5m=1221:l=m:h=54272:j=j+1aN3:on-(j<>g)gO4:j=pE(a):pOa,n:ifj<4tHa=a-a(j):g=j:gO4
6pOl,n:pOy,pE(y)-1:x=rN(0)*720:on-(pE(m+x)<>n)gO6:?"{home}{reverse on}use i,k,j,l to move":l=m+x
7pOl,w+1:pOh+l,2:gEz$:ifz$tHs=aS(z$):e=saN1:c=s-75+e:c=sG(c)
8fOi=0to7:pO14592+i,0:nE:b=a+c*(39*e+1):on-(pE(b)<>waNpE(b)<>w-3)gO9:gO7
9on-(pE(b)=w+1)gO6:pOb,132:pOb+h,1:pOa,n:a=b:gO7:dA24,24,60,126,185,56,76,102

Tip: Copy/paste the program-Code into CBM prg Studio (http://www.ajordison.co.uk/)

Uncompressed source:
===================
0a=1186:w=163:v=56334:a$="{reverse on}{yellow} ":d$=a$:print"{white}{clear}{reverse on}wait...":b$="{white}{reverse on}#":c$=b$:pokev,peek(v)and254
1forz=0to36:b$=b$+c$:a$=a$+d$:next:poke1,peek(1)and251:fori=0to367:pokei+15368,peek(i+54280)
2next:poke1,peek(1)or4:a(0)=-2:a(1)=-80:a(3)=80:e$=b$+c$+c$:printe$;:forf=0to20:printc$a$c$;
3next:printe$;:y=53280:pokev,peek(v)or1:pokey-8,peek(y-8)or14:fori=0to7:readf:poke15392+i,f:next
4a(2)=2:n=32:b=a+a(j):ifpeek(b)=w-3thenpokeb,j:pokea+a(j)/2,n:a=b:j=int(rnd(0)*4):g=j:goto4
5m=1221:l=m:h=54272:j=j+1and3:on-(j<>g)goto4:j=peek(a):pokea,n:ifj<4thena=a-a(j):g=j:goto4
6pokel,n:pokey,peek(y)-1:x=rnd(0)*720:on-(peek(m+x)<>n)goto6:print"{home}{reverse on}use i,k,j,l to move":l=m+x
7pokel,w+1:pokeh+l,2:getz$:ifz$thens=asc(z$):e=sand1:c=s-75+e:c=sgn(c)
8fori=0to7:poke14592+i,0:next:b=a+c*(39*e+1):on-(peek(b)<>wandpeek(b)<>w-3)goto9:goto7
9on-(peek(b)=w+1)goto6:pokeb,132:pokeb+h,1:pokea,n:a=b:goto7:data24,24,60,126,185,56,76,102

Tip: Copy/paste the program-Code into CBM prg Studio (http://www.ajordison.co.uk/)

Code comment
============
 LINE 0: 
- Some variables are initialized:
a=1186:w=163:v=56334
a contains the location of the starting point on the tracing screen of 
the labyrinth; it also indicates where the little man will appear.
w contains the border of the mazes character.
v contains the control register A.

- The word "WAIT ..." appears:
?"{white}{clear}{reverse on}wait..."

- The string a$ contains the yellow space in reverse:
a$="{reverse on}{yellow} "

- The string b$ contains the reverse # character of white color that 
will constitute the external perimeter of the labyrinth:
b$="{white}{reverse on}#"

- Disable the keyboard and the I/O functions:
pokev, peek (v) and254

=========================================================================
 LINE 1: 
- An additional 37 characters equal to those already contained in the 
strings are added to the variables a$ and b$, in order to cover the 
entire length of the screen (40 characters):
1forz=0to36:b$=b$+c$:a$=a$+d$:next

- The character ROM is positioned starting from location 53248:
poke1, peek (1) and251 

- Move 46 characters (368 = 46 * 8) from the ROM locations (54280 to 
54647), to RAM starting from location 15368:
fori = 0to367: pokei + 15368, peek (i + 54280)
I have moved the characters in reverse from 'a' to '.'.

=========================================================================
 LINE 2: 
- Switch I/O back into ROM for normal operation:
poke1,peek(1)or4

- Initializes arrays with values indicating two characters on the left (-
2), two at the top (-80) and two at the bottom (80):
a(0)=-2:a(1)=-80:a(3)=80

- Complete the strings to be printed and print them:
e$=b$+c$+c$:
printe$;:
forf=0to20:
	printc$a$c$

=========================================================================
 LINE 3: 
- Turns interrupts functions and keyboard on:
pokev,peek(v)or1
 
- Set char pointer to mem. 14336:
pokey-8,peek(y-8)or14

- Rewrite the new character into the reversed d (from 15392 to 15399):
fori=0to7:
	readf:
	poke15392+i,f:
next

=========================================================================
 LINE 4: 
- Initializes a(2) with value indicating two characters to the right 
and n with value indicating a space:
a(2)=2:n=32

- Variable b is updated; a decides the starting point (location 1186) 
from which to trace the labyrinth and the to take during the 
constructions direction is decided by a(j):
b=a+a(j)

- Check collision with space characters in reverse (w-3 = 160):
ifpeek(b)=w-3then 

- In this case:
1) writes the character corresponding to the value j (@, a, b, c) and 
behind it adds a space to draw the tunnels of the labyrinth:
pokeb,j:pokea+a(j)/2,n

2) Update a to the new value of b:
a=b

3) Assign to j a random value between 0 and 3:
j=int(rnd(0)*4)

4) Update the variable g with the new value of j:
g=j

5) go to line 4:
goto4

=========================================================================
 LINE 5:
- m and l is the start location of treasure on the screen:
m=1206:l=m

- h is the color address to add to screen location:
h=54272

- j alternately takes the values 1 (= 1AND3), 2 (= 2AND3), 3 (= 3AND3) 
and 0 (= 4AND3):
j=j+1and3

- The backtracking algorithm is implemented: it begins to deposit the 
characters @, a, b and c during the construction of the maze. If you 
cannot move further forward, try the other random directions, otherwise 
go back on your steps if there are no other yellow squares:
on-(j<>g)
	goto4:
j=peek(a):
pokea,n:
ifj<4then
	a=a-a(j):
	g=j:
	goto4

=========================================================================
 LINE 6: 
- Deletes the treasure:
pokel,n

- Changes background color:
pokey,peek(y)-1

- Creates a new random position of the treasure:
x=rnd(0)*720

- Try to locate in the free space:
on-(peek(m+x)<>n)goto6

- Calculate the new location for the treasure:
l=m+x

=========================================================================
 LINE 7: 
- Updates the position of the treasure and colors it red:
pokel,w+1:pokeh+l,2

- Waits for the I, J, K, L keys to be pressed for the little man to move. 
I used a Fabrizio Caruso's trick (*):
getz$:
ifz$then
       s=asc(z$):
       e=sand1:
       c=s-75+e:
       c=sgn(c)

=========================================================================
 LINE 8: 
- Reset the character space location (32*8+14336) in RAM:
fori=0to7:
	poke14592+i,0:
next

- Updates the position of little man:
b=a+c*(39*e+1)

- Check obstacles (edge and wall of the labyrinth):
on-(peek(b)<>wandpeek(b)<>w-3)
       goto9:
goto7

=========================================================================
 LINE 9: 
- Updates the little mans position, colors it white and deletes the old 
position:
pokeb,132:pokeb+h,1:pokea,n:a=b:

- Check if it found the treasure or not:
on-(peek(b)=w+1)goto6

- Data for the new d in reverse character for the little man:
data24,24,60,126,185,56,76,102

=========================================================================
(*) It uses an interpolating formula that computes the offset from the 
ASCII code of the pressed key. 
(thanks to Fabrizio Caruso)

- It exploits the special symmetry of the ASCII codes of the keys I J K 
L:
I and K have odd codes and a distance of 2 bytes
J and L have even codes and a distance of 2 bytes
I and K have odd ASCII codes
J and L have even ASCII codes
- So, given s=ASC(a$) with a$ either I or J or K or L, we update the 
position p with
p=p+c*(39*e+1) 
 where
e=s and 1 -> parity of the code, i.e., vertical vs horizontal movement
c=s-75+e -> -1 for left/up vs +1 for right/down
39e+1 -> vertical vs horizontal offset absolute value, i.e., 1 vs 40
